extends Node

signal update_checkpoints

@export var SAVE_PATH := "user://data.sav"
@onready var color_rect: ColorRect = $ColorRect


func _ready() -> void:
	color_rect.color.a = 0
	color_rect.hide()


func change_scene(path: String, params := {}) -> void:
	# Available parameters:
	# - duration: the time used to let the scene fade in and out
	# - init: the action will be called before the scene changes
	# - entry_point: the name of an EntryPoint in the new scene
	# - position: the position where the player will be placed in the new scene
	# - is_new_game: it will disable the player entering animation to new 
	#				 EntryPoint, when its value is true
	
	var duration := params.get("duration", 0.2) as float
	
	var tree := get_tree()
	
	tree.paused = true
	
	color_rect.show()
	var tween := create_tween()
	tween.set_pause_mode(Tween.TWEEN_PAUSE_PROCESS)  # 避免转场动画在上面游戏暂停时也暂停
	tween.tween_property(color_rect, "color:a", 1, duration)
	await tween.finished
	
	if "init" in params: params.init.call()
	
	tree.change_scene_to_file(path)
	await tree.tree_changed
	
	var direction := 1
	var is_entering := false
	if tree.current_scene is BaseLevel:
		if "entry_point" in params:
			for node in tree.get_nodes_in_group("entry_points"):
				if node.name != params.entry_point: continue
				GlobalGameData.playerRespawnPoints.append({
					pos=node.global_position,
					name="ENTRY_POINT"
				})
				direction = GlobalGameData.player_direction if node.direction == 0 else node.direction
				is_entering = true
				break
		if "position" in params:
			GlobalGameData.playerRespawnPoints.append({
				pos=params.position,
				name="SETTED_POS"
			})
		
		# 在切换场景时播放进入动画
		if not params.get("is_new_game", false):
			tree.current_scene.reset_player(
				direction, 
				is_entering, 
				params.get("entering_mode", Player.EnteringMode.NORMAL)
			)
	
	tree.paused = false  # 重新开始整个场景
	
	tween = create_tween()
	tween.set_pause_mode(Tween.TWEEN_PAUSE_PROCESS)  # 避免两个黑屏动画同时播放
	tween.tween_property(color_rect, "color:a", 0, duration)
	await  tween.finished
	color_rect.hide()


func save_game() -> void:
	var scene := get_tree().current_scene
	var scene_name := scene.scene_file_path.get_file().get_basename()
	
	# Create save data
	var data := {
		save_time = Time.get_datetime_string_from_system(),
		scene = scene.scene_file_path,
		global_game_data = GlobalGameData.to_dict(),
		player = {
			position = {
				x = scene.player.global_position.x,
				y = scene.player.global_position.y,
			},
			direction = scene.player.direction,
		}
	}
	
	# Save data to file
	var json := JSON.stringify(data)
	var file := FileAccess.open(SAVE_PATH, FileAccess.WRITE)
	if file: file.store_string(json)


func load_game() -> void:
	var file := FileAccess.open(SAVE_PATH, FileAccess.READ)
	if not file: return
	
	var json := file.get_as_text()
	var data := JSON.parse_string(json) as Dictionary
	
	change_scene(data.scene,{
		direction = data.player.direction,
		position = Vector2(
			data.player.position.x,
			data.player.position.y,
		),
		init = func ():
			GlobalGameData.from_dict(data.global_game_data)
	})


func new_game() -> void:
	change_scene("res://levels/level.tscn", {
		duration = 0.5,
		is_new_game = true,
		init = func():
			GlobalGameData.reset_player_stats()
	})
